#include "memory\linearallocator.h"
#include "config\config_types.h"

namespace ssmt
{
	namespace allocator
	{
		LinearAllocator::LinearAllocator(void* start, void* end)
		{
			PointerMagic pm;
			pm.as_void_ptr = start;
			_start = pm.as_char_ptr;
			_current = _start;
			pm.as_void_ptr = end;
			_end = pm.as_char_ptr;
		}

		//Although not needed we store the allocation size infront of the Boundschecking.
		//So we actully use an offset +4 for the calculations and store size_t at alignedptr-8
		//but we will return alignedptr-4 (normal offset) to ensure the rest will still work 
		void* LinearAllocator::allocate(size_t size, size_t alignment, size_t offset)
		{
			//((a + (b-1)) & -b)
			PointerMagic pm3;
			pm3.as_char_ptr = _current + offset + 4; //4 byte for size storage
			pm3.as_intptr_t = ((pm3.as_intptr_t + (alignment-1)) & -static_cast<int>(alignment));
			void* ptr2 = pm3.as_char_ptr - offset;
			ptr2;

			void * userPtr = ptr2;

			_current += size;
			if (_current >= _end)
			{
				// out of memory
				return nullptr;
			}
			
			void* sizePtr = pm3.as_char_ptr - offset - 4;
			*static_cast<int*>(sizePtr) = size;
			return userPtr;
		}

		void LinearAllocator::deallocate(void* ptr)
		{
			PointerMagic pm;
			pm.as_void_ptr = ptr;
			pm.as_char_ptr -= 4;
			_current = pm.as_char_ptr;
			memset(pm.as_char_ptr,0xCC,getAllocationSize(ptr)+4);
		}
		
		void LinearAllocator::reset()
		{

		}

		size_t LinearAllocator::getAllocationSize(void* ptr)
		{
			PointerMagic pm;
			pm.as_void_ptr = ptr;
			pm.as_char_ptr -= 4;
			return *static_cast<int*>(pm.as_void_ptr);
		}
	} //namespace allocator
} //namespace ssmt